package com.ruoyi.web.controller.redis;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Component // 声明为Spring组件
public class RedisUtils {
    private final RedisTemplate<String, Object> redisTemplate;

    @Autowired // 自动注入RedisTemplate
    public RedisUtils(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    // 私有构造函数，防止实例化
//    private RedisUtils() {}

    /**
     * 创建存储构建器
     */
    public  <T> Builder<T> builder(Class<T> clazz) {
        return new Builder<>(redisTemplate, clazz);
    }

    /**
     * 构建器类
     */
    public static class Builder<T> {
        private final RedisTemplate<String, Object> redisTemplate;
        private final Class<T> clazz;
        private String keyPrefix;
        private String indexKey;
        private List<T> dataList;
        private Function<T, String> keyExtractor;
        private Function<T, String> fieldExtractor;
        private String secondaryIndex;
        private long expireTime;

        private Builder(RedisTemplate<String, Object> redisTemplate, Class<T> clazz) {
            this.redisTemplate = redisTemplate;
            this.clazz = clazz;
        }

        public Builder<T> keyPrefix(String keyPrefix) {
            this.keyPrefix = keyPrefix;
            return this;
        }

        public Builder<T> indexKey(String indexKey) {
            this.indexKey = indexKey;
            return this;
        }

        public Builder<T> dataList(List<T> dataList) {
            this.dataList = dataList;
            return this;
        }

        public Builder<T> keyExtractor(Function<T, String> keyExtractor) {
            this.keyExtractor = keyExtractor;
            return this;
        }

        public Builder<T> fieldExtractor(Function<T, String> fieldExtractor) {
            this.fieldExtractor = fieldExtractor;
            return this;
        }

        public Builder<T> secondaryIndex(String secondaryIndex) {
            this.secondaryIndex = secondaryIndex;
            return this;
        }

        public Builder<T> expireTime(long expireTime) {
            this.expireTime = expireTime;
            return this;
        }

        /**
         * 批量存储数据到Redis
         */
        public void store() {
            if (CollectionUtils.isEmpty(dataList)) {
                return;
            }

            ObjectMapper objectMapper = new ObjectMapper();
            RedisSerializer<String> stringSerializer = new StringRedisSerializer();

            // 使用管道批量操作
            redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
                for (T data : dataList) {
                    try {
                        String keySuffix = keyExtractor.apply(data);
                        String key = keyPrefix + ":" + keySuffix;
                        String dataJson = objectMapper.writeValueAsString(data);

                        // 存储对象到Hash
                        byte[] keyBytes = stringSerializer.serialize(key);
                        byte[] fieldBytes = stringSerializer.serialize("data");
                        byte[] valueBytes = stringSerializer.serialize(dataJson);

                        if (keyBytes != null && fieldBytes != null && valueBytes != null) {
                            connection.hSet(keyBytes, fieldBytes, valueBytes);

                            // 添加到索引集合
                            byte[] indexKeyBytes = stringSerializer.serialize(indexKey);
                            if (indexKeyBytes != null) {
                                connection.sAdd(indexKeyBytes, keyBytes);
                            }

                            // 设置过期时间
                            if (expireTime > 0) {
                                connection.expire(keyBytes, expireTime);
                            }
                        }
                    } catch (Exception e) {
                        throw new RuntimeException("序列化对象失败", e);
                    }
                }

                // 设置索引集合的过期时间
                if (expireTime > 0) {
                    byte[] indexKeyBytes = stringSerializer.serialize(indexKey);
                    if (indexKeyBytes != null) {
                        connection.expire(indexKeyBytes, expireTime);
                    }
                }
                return null;
            });
        }

        /**
         * 批量存储数据到Redis，并为指定字段创建二级索引
         */
        public void storeWithSecondaryIndex() {
            if (CollectionUtils.isEmpty(dataList) || fieldExtractor == null || secondaryIndex == null) {
                throw new IllegalArgumentException("缺少必要的参数: dataList, fieldExtractor 或 secondaryIndex");
            }

            ObjectMapper objectMapper = new ObjectMapper();
            RedisSerializer<String> stringSerializer = new StringRedisSerializer();

            // 使用管道批量操作
            redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
                for (T data : dataList) {
                    try {
                        String keySuffix = keyExtractor.apply(data);
                        String key = keyPrefix + ":" + keySuffix;
                        String dataJson = objectMapper.writeValueAsString(data);
                        String fieldValue = fieldExtractor.apply(data);
                        String secondaryIndexKey = secondaryIndex + ":" + fieldValue;

                        // 存储对象到Hash
                        byte[] keyBytes = stringSerializer.serialize(key);
                        byte[] fieldBytes = stringSerializer.serialize("data");
                        byte[] valueBytes = stringSerializer.serialize(dataJson);

                        if (keyBytes != null && fieldBytes != null && valueBytes != null) {
                            connection.hSet(keyBytes, fieldBytes, valueBytes);

                            // 添加到主索引集合
                            byte[] indexKeyBytes = stringSerializer.serialize(indexKey);
                            if (indexKeyBytes != null) {
                                connection.sAdd(indexKeyBytes, keyBytes);
                            }

                            // 添加到二级索引集合
                            byte[] secondaryIndexKeyBytes = stringSerializer.serialize(secondaryIndexKey);
                            if (secondaryIndexKeyBytes != null) {
                                connection.sAdd(secondaryIndexKeyBytes, keyBytes);

                                // 设置二级索引集合的过期时间
                                if (expireTime > 0) {
                                    connection.expire(secondaryIndexKeyBytes, expireTime);
                                }
                            }

                            // 设置过期时间
                            if (expireTime > 0) {
                                connection.expire(keyBytes, expireTime);
                            }
                        }
                    } catch (Exception e) {
                        throw new RuntimeException("序列化对象失败", e);
                    }
                }

                // 设置主索引集合的过期时间
                if (expireTime > 0) {
                    byte[] indexKeyBytes = stringSerializer.serialize(indexKey);
                    if (indexKeyBytes != null) {
                        connection.expire(indexKeyBytes, expireTime);
                    }
                }
                return null;
            });
        }

        /**
         * 分页查询数据
         */
        public PageResult<T> pageQuery(int pageNum, int pageSize, Predicate<T> condition) {
            return pageQuery(pageNum, pageSize, condition, null);
        }

        /**
         * 分页查询数据（带排序）
         */
        public PageResult<T> pageQuery(int pageNum, int pageSize,
                                       Predicate<T> condition, Comparator<T> comparator) {
            if (pageNum < 1) pageNum = 1;
            if (pageSize < 1) pageSize = 10;

            long start = (pageNum - 1) * pageSize;

            try {
                // 获取所有键
                Set<String> keys = redisTemplate.opsForSet().members(indexKey)
                        .stream()
                        .map(obj -> (String) obj)
                        .collect(Collectors.toSet());

                if (CollectionUtils.isEmpty(keys)) {
                    return new PageResult<>(Collections.emptyList(), 0, pageNum, pageSize);
                }

                // 批量获取数据
                List<Object> values = new ArrayList<>();
                for (String key : keys) {
                    Object value = redisTemplate.opsForHash().get(key, "data");
                    values.add(value);
                }

                // 转换并过滤数据
                List<T> allData = new ArrayList<>();
                ObjectMapper objectMapper = new ObjectMapper();
                for (Object value : values) {
                    if (value != null) {
                        try {
                            T item = objectMapper.readValue(value.toString(), clazz);
                            if (condition == null || condition.test(item)) {
                                allData.add(item);
                            }
                        } catch (Exception e) {
                            // 忽略无法反序列化的数据
                        }
                    }
                }

                // 排序
                if (comparator != null) {
                    allData.sort(comparator);
                }

                // 手动分页
                List<T> resultList = allData.stream()
                        .skip(start)
                        .limit(pageSize)
                        .collect(Collectors.toList());

                // 获取总数
                long total = allData.size();

                return new PageResult<>(resultList, total, pageNum, pageSize);
            } catch (Exception e) {
                throw new RuntimeException("从Redis分页查询数据失败", e);
            }
        }

        /**
         * 根据ID获取单个对象
         */
        public T getById(String id) {
            try {
                String key = keyPrefix + ":" + id;
                Object value = redisTemplate.opsForHash().get(key, "data");
                if (value != null) {
                    ObjectMapper objectMapper = new ObjectMapper();
                    return objectMapper.readValue(value.toString(), clazz);
                }
                return null;
            } catch (Exception e) {
                throw new RuntimeException("从Redis获取对象失败", e);
            }
        }

        /**
         * 批量获取对象
         */
        public List<T> getByIds(List<String> ids) {
            if (CollectionUtils.isEmpty(ids)) {
                return Collections.emptyList();
            }

            try {
                List<String> keys = ids.stream()
                        .map(id -> keyPrefix + ":" + id)
                        .collect(Collectors.toList());

                // 批量获取数据
                List<Object> values = new ArrayList<>();
                for (String key : keys) {
                    Object value = redisTemplate.opsForHash().get(key, "data");
                    values.add(value);
                }

                List<T> result = new ArrayList<>();
                ObjectMapper objectMapper = new ObjectMapper();
                for (Object value : values) {
                    if (value != null) {
                        try {
                            T item = objectMapper.readValue(value.toString(), clazz);
                            result.add(item);
                        } catch (Exception e) {
                            // 忽略无法反序列化的数据
                        }
                    }
                }

                return result;
            } catch (Exception e) {
                throw new RuntimeException("从Redis批量获取对象失败", e);
            }
        }

        /**
         * 删除对象
         */
        public void delete(String id) {
            String key = keyPrefix + ":" + id;

            // 从索引集合中移除
            redisTemplate.opsForSet().remove(indexKey, key);

            // 删除对象
            redisTemplate.delete(key);
        }

        /**
         * 批量删除对象
         */
        public void batchDelete(List<String> ids) {
            if (CollectionUtils.isEmpty(ids)) {
                return;
            }

            List<String> keys = ids.stream()
                    .map(id -> keyPrefix + ":" + id)
                    .collect(Collectors.toList());

            // 从索引集合中移除
            redisTemplate.opsForSet().remove(indexKey, keys.toArray());

            // 批量删除对象
            redisTemplate.delete(keys);
        }

        /**
         * 获取索引集合大小
         */
        public long getIndexSize() {
            Long size = redisTemplate.opsForSet().size(indexKey);
            return size != null ? size : 0;
        }

// 在 Builder 类中添加以下方法

        /**
         * 删除当前Builder配置的所有相关数据
         */
        public void deleteAll() {
            if (keyPrefix == null || indexKey == null) {
                throw new IllegalStateException("keyPrefix and indexKey must be set before calling deleteAll");
            }

            // 获取indexKey集合中的所有键
            Set<Object> keys = redisTemplate.opsForSet().members(indexKey);
            if (!CollectionUtils.isEmpty(keys)) {
                // 删除所有数据键
                redisTemplate.delete(keys.toString());

                // 删除indexKey集合本身
                redisTemplate.delete(indexKey);
            }

            // 使用模式匹配删除所有与keyPrefix相关的键
            Set<String> patternKeys = redisTemplate.keys(keyPrefix + ":*");
            if (!CollectionUtils.isEmpty(patternKeys)) {
                redisTemplate.delete(patternKeys);
            }
        }

        /**
         * 根据ID列表删除数据（同时从indexKey集合中移除）
         * @param ids ID列表
         */
        public void deleteByIds(List<String> ids) {
            if (CollectionUtils.isEmpty(ids)) {
                return;
            }

            // 生成完整的键列表
            List<String> keys = ids.stream()
                    .map(id -> keyPrefix + ":" + id)
                    .collect(Collectors.toList());

            // 从索引集合中移除
            redisTemplate.opsForSet().remove(indexKey, keys.toArray());

            // 删除数据键
            redisTemplate.delete(keys);
        }

        /**
         * 清空indexKey集合但不删除数据
         */
        public void clearIndex() {
            if (indexKey == null) {
                throw new IllegalStateException("indexKey must be set before calling clearIndex");
            }

            // 删除indexKey集合
            redisTemplate.delete(indexKey);
        }

        /**
         * 删除所有数据但不影响indexKey集合
         */
        public void deleteAllData() {
            if (keyPrefix == null) {
                throw new IllegalStateException("keyPrefix must be set before calling deleteAllData");
            }

            // 获取indexKey集合中的所有键
            Set<Object> keys = redisTemplate.opsForSet().members(indexKey);
            if (!CollectionUtils.isEmpty(keys)) {
                // 删除所有数据键
                redisTemplate.delete(keys.toString());
            }

            // 使用模式匹配删除所有与keyPrefix相关的键（除了indexKey）
            Set<String> patternKeys = redisTemplate.keys(keyPrefix + ":*");
            if (!CollectionUtils.isEmpty(patternKeys)) {
                // 过滤掉indexKey
                patternKeys = patternKeys.stream()
                        .filter(key -> !key.equals(indexKey))
                        .collect(Collectors.toSet());

                if (!CollectionUtils.isEmpty(patternKeys)) {
                    redisTemplate.delete(patternKeys);
                }
            }
        }

    }

    /**
     * 分页结果类
     */
    public static class PageResult<T> {
        private List<T> list;
        private long total;
        private int pageNum;
        private int pageSize;
        private int pages;

        public PageResult(List<T> list, long total, int pageNum, int pageSize) {
            this.list = list;
            this.total = total;
            this.pageNum = pageNum;
            this.pageSize = pageSize;
            this.pages = (int) Math.ceil((double) total / pageSize);
        }

        // Getter方法
        public List<T> getList() { return list; }
        public long getTotal() { return total; }
        public int getPageNum() { return pageNum; }
        public int getPageSize() { return pageSize; }
        public int getPages() { return pages; }

        @Override
        public String toString() {
            return "PageResult{" +
                    "list=" + list +
                    ", total=" + total +
                    ", pageNum=" + pageNum +
                    ", pageSize=" + pageSize +
                    ", pages=" + pages +
                    '}';
        }
    }

    // 添加一些便利的静态方法

    /**
     * 快速存储单个对象
     */
    public  <T> void storeSingle(Class<T> clazz,
                                       String keyPrefix, String indexKey, T data,
                                       Function<T, String> keyExtractor, long expireTime) {
        builder(clazz)
                .keyPrefix(keyPrefix)
                .indexKey(indexKey)
                .dataList(Collections.singletonList(data))
                .keyExtractor(keyExtractor)
                .expireTime(expireTime)
                .store();
    }

    /**
     * 快速读取单个对象
     */
    public  <T> T readSingle(Class<T> clazz,
                                   String keyPrefix, String id) {
        return builder(clazz)
                .keyPrefix(keyPrefix)
                .getById(id);
    }

    /**
     * 快速读取所有对象
     */
    public  <T> List<T> readAll(Class<T> clazz,
                                      String indexKey) {
        return builder(clazz)
                .indexKey(indexKey)
                .pageQuery(1, Integer.MAX_VALUE, null)
                .getList();
    }

    /**
     * 快速分页查询
     */
    public  <T> PageResult<T> quickPageQuery(Class<T> clazz,
                                                   String indexKey, int pageNum, int pageSize) {
        return builder(clazz)
                .indexKey(indexKey)
                .pageQuery(pageNum, pageSize, null);
    }
}
